package cn.jiedanba.cacert.common.ca.ocsp;

import java.security.cert.X509Certificate;
import java.util.Date;

import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
import org.bouncycastle.cert.ocsp.CertificateStatus;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
import org.bouncycastle.cert.ocsp.Req;
import org.bouncycastle.cert.ocsp.RespID;
import org.bouncycastle.cert.ocsp.RevokedStatus;
import org.bouncycastle.cert.ocsp.UnknownStatus;
import org.bouncycastle.cert.ocsp.jcajce.JcaBasicOCSPRespBuilder;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;

import cn.jiedanba.cacert.common.bc.base.BaseSecurity;
import cn.jiedanba.cacert.common.ca.algorithm.AlgorithmConstant;
import cn.jiedanba.cacert.common.ca.algorithm.SignatureAlgorithms;
import cn.jiedanba.cacert.common.ca.cert.enums.CertStatusEnum;
import cn.jiedanba.cacert.common.ca.ocsp.domain.OCSP;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class OCSPUtil extends BaseSecurity {

	/**
	 * ocsp签名
	 * 
	 * @param ocsp
	 * @return
	 */
	public static byte[] sign(OCSP ocsp) {
		try {

			byte[] enc = null;
			OCSPReq ocspReq = ocsp.getOcspReq();
			Req[] requests = ocsp.getRequests();

			CertificateStatus cs = new UnknownStatus();

			// 注销
			if (ocsp.getStatus().equals(CertStatusEnum.REVOKE.code)) {
				cs = new RevokedStatus(ocsp.getRevokeDate(), ocsp.getRevokeReason());
			} else {
				cs = CertificateStatus.GOOD;
			}
			X509Certificate ocspSign = ocsp.getOcspSignCert();
			DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();

			String signatureAlgorithm = AlgorithmConstant.SHA256WithRSA;
			String ocspSignAlgOid = ocspSign.getSigAlgOID();

			if (ocspSignAlgOid.equalsIgnoreCase(SignatureAlgorithms.getSignatureOid(AlgorithmConstant.SM3WithSM2))) {
				signatureAlgorithm = AlgorithmConstant.SM3WithSM2;

			} else if (ocspSignAlgOid
					.equalsIgnoreCase(SignatureAlgorithms.getSignatureOid(AlgorithmConstant.SHA1WithRSA))) {
				signatureAlgorithm = AlgorithmConstant.SHA1WithRSA;

			} else if (ocspSignAlgOid
					.equalsIgnoreCase(SignatureAlgorithms.getSignatureOid(AlgorithmConstant.SHA256WithRSA))) {
				signatureAlgorithm = AlgorithmConstant.SHA256WithRSA;

			} else if (ocspSignAlgOid
					.equalsIgnoreCase(SignatureAlgorithms.getSignatureOid(AlgorithmConstant.SHA256WithECDSA))) {
				signatureAlgorithm = AlgorithmConstant.SHA256WithECDSA;

			}
			DigestCalculator digCalc = digCalcProv.get(RespID.HASH_SHA1);
			BasicOCSPRespBuilder respGen = new JcaBasicOCSPRespBuilder(ocspSign.getPublicKey(), digCalc);

			// OCSP响应加入随机数
			Extension extValue = ocspReq.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
			if (extValue != null) {
				ExtensionsGenerator extGen = new ExtensionsGenerator();
				extGen.addExtension(extValue);
				respGen.setResponseExtensions(extGen.generate());
			}
			Date thisUpdate = new Date();
			respGen.addResponse(requests[0].getCertID(), cs, thisUpdate, ocsp.getNextUpdate(), null);

			X509CertificateHolder holder = new X509CertificateHolder(ocspSign.getEncoded());
			X509CertificateHolder[] chain = new X509CertificateHolder[] { holder };
			// 生成OCSP响应
			BasicOCSPResp ocspResp = respGen.build(
					new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BC).build(ocsp.getOcspPk()), chain,
					new Date());
			OCSPRespBuilder rGen = new OCSPRespBuilder();

			enc = rGen.build(OCSPRespBuilder.SUCCESSFUL, ocspResp).getEncoded();
			return enc;
		} catch (Exception e) {
			throw new RuntimeException("OCSP签名失败", e);
		}
	}
}
